/*
*	Implementacion del TAD pertADT
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <graphviz/gvc.h>

#include "../include/pert.h"
#include "../include/digraph.h"
#include "../include/queue.h"


/* CONSTANTES */
#define MAX_DESCRIPCION 100	/* descripcion para usar en el parser */
#define MAXBUFFER	100		/* buffer para el parser */
#define MAXPREDEC	15		/* uso del parser */
#define MAX_TASK_PRED 21
#define	BLOQUE_ACT	20
#define	MAXDETALLE	100
#define	MAX_ID	20
#define TONUMBER(c) ((c) - '0')

/* Estructura con la informacion de una actividad que se almacena en la arista */
typedef struct 
{
	char ID [MAX_ID + 1];	/* codigo de identificacion de la actividad */
	char descripcion[MAX_DESCRIPCION+1];	/* descripcion mas detallada de la actividad */
	int duracion; /* duracion media de la actividad */
	int margen;	/* margen de holgura de la tarea */
	int ct; /* tiempo mas cercano de terminacion para una actividad determinada */
	int lt; /* tiempo mas lejano de terminacion para una actividad determinada */
	int tag; /* para ir iterando por las aristas y reconocer cuales ya se visito */
	int vecPredec[MAX_TASK_PRED];
} actividadT;

/* Estructura con la informacion de tiempos, se almacena en los nodos */
typedef struct 
{
	int nombre;
	int ci;	/* tiempo mas cercano de inicio para una actividad determinada */
	int li; /* tiempo mas lejano de inicio para una actividad determinada */
} infoNodoT;


/* Estructura de informacion de nodos de una actividad */
typedef struct nodesActivity
{
	int nodeInicio; /* nodo inicial de la actividad */
	int nodeFin;   /*Nodo final de la actividad */
	int logicErase;  /* en 1 si esta borrada */
}nodesActivity;

struct pertCDT
{
	digraphADT digraph;
	queueADT cola;
	actividadT* vecActivities;
	nodesActivity* vecNodes;
	nodesActivity* vecFic;
	int cant;
	int bloque;
};

typedef enum { INICIAL, ERROR, FIN, POS_VACIO, POS_DIG, POS_MASDIG, POS_PRIMERO }estadoT;

/*
*-----------------------------------
*  		FUNCIONES ESTATICAS |
*-----------------------------------
*/


/* Funciones estaticas de InsertTask */
static int BuscarActividad( pertADT pert, char* Actname );
static int VerifyInsertion( pertADT pert, actividadT* NewAct,char* predecesoras, char* sucesoras );
static int FindPosition(pertADT pert);	

/* Funciones estaticas de ModifyTask */
int BuscarFicticia( nodesActivity* ficticias, int nodosrc, int nodotgt );

static int GetInt( char *s );
static int Power(int pow);

/* Funciones estaticas de LoadPert */
static pertADT NewPert( void );
static int LoadActivities( FILE* archivo, actividadT** actividades, int* pertblock );
static digraphADT ArmaDigrafo( pertADT pert, int cantactividades );
static int getID(char **buffer, int dimBuffer, actividadT *actividad);
static int getDetalle(char **buffer, actividadT *actividad, int dimDetalle);
static int getNum(char **buffer, int dimBuffer);
static int getPredec(char **buffer, actividadT *vecActividades, actividadT *actividad, int numTarea);
static int Getprec( actividadT* vec_act, int* actpredec, int indice );
static void GetVecSum(digraphADT digrafo, int **vecSum);
static int CrearSumidero(pertADT pert, int *vecSum);
static int FindNodeSrc(actividadT *vecActividad, nodesActivity *vecNodos, int nodoFin, int cantActividades);
static int CmpNodes( nodeT nodo1, nodeT nodo2);
static int validatePredec(char *actPre, actividadT *vecActividad, int numTarea);

/* Funciones estaticas de GetCPM */
static void UnmarkEdges	(digraphADT digrafo );
static void UnmarkRec( digraphADT digrafo, nodeT node, edgeT arista );
static void CPMRec( digraphADT grafo, nodeT node, queueADT cola, edgeT arista, int* fin );
static void UnmarkTimesRec( digraphADT digrafo, nodeT node );
static void UnmarkTimes (digraphADT digrafo );


/* Funciones estaticas de CalcEarlyTimes */
static void CalcEarlyRec( digraphADT grafo, nodeT node, edgeT arista );

/* Funciones estaticas de CalcLateTimes */
static void CalcLateRec( digraphADT digrafo, nodeT node, edgeT arista );

/* Funciones estaticas de CalcMargins */
static void CalcMarginsRec( digraphADT digrafo, nodeT node, edgeT arista );

/* Funciones estaticas de CreateDotFile */
static char * ColorChooser(int margen);

/* Funciones estaticas de Calendar */

static char * GetProyectStart(int frmlength);
static char * transfToDate(int num, int cantDigits);
static char * GetActTime(char * initDate, TimeUnit unit, int frmLength, int startTime);

static int checkStart(int days, int months, int years, int hours, int minutes);
static int CalcDays(int months, int years);
static int addUnits(int startTime, char ** newDate, int pos, int timeLimit);
static int addSpecial(int startTime, char ** newDate, char * month, char * year);

pertADT
LoadPert( FILE* archivo )
{
	pertADT pert;
	int cantactividades;
	int *vecSum;
	
	pert = NewPert();
	/* Creo el vector de actividades */
	if( (cantactividades = LoadActivities( archivo, &(pert->vecActivities), &(pert->bloque) )) == -1) 
	{ 
		fprintf(stderr, "LoadPert: no se pudo cargar el archivo....abortando\n");
		
		return NULL;
	}
	pert->cant = cantactividades;
	pert->digraph = ArmaDigrafo( pert, cantactividades );
	/* Arma el digrafo y lo coloca en el campo digrafo de pert */

	vecSum = malloc(sizeof(int) * pert -> cant);
	
	/* Creo un solo sumidero */
	GetVecSum(pert -> digraph, &vecSum);
	CrearSumidero(pert, vecSum);
	free( vecSum );
	
	UnmarkTimes(pert -> digraph);
	
	GetCPM(pert);
	
	return pert;
}


int
GetCPM( pertADT pert )
{
	digraphADT digrafo;
	int fin = 0;
	nodeT node;
	edgeT element;
		
	digrafo = pert->digraph;
	
	pert->cola = NewQueue();
	
	CalcEarlyTimes( pert );
	CalcLateTimes( pert );
	CalcMargins( pert );
		
	UnmarkEdges( digrafo );
	
	SetBeginDiGraph( digrafo );
	node = GetNextNode( digrafo );
		
	CPMRec( digrafo, node, pert->cola, element, &fin );
		
	if( QueueIsEmpty( pert->cola ) )
		return 1;
	return 0;
}

void
CalcEarlyTimes( pertADT pert )
{
	nodeT node;
	edgeT arista;
	digraphADT digrafo;
		
	digrafo = pert->digraph;
	UnmarkEdges( digrafo );
	
	SetBeginDiGraph( digrafo );
	node = GetNextNode( digrafo );
	
	((infoNodoT*)node)->ci = 0;
	((infoNodoT*)node)->li = 0;
	
	CalcEarlyRec( digrafo, node, arista );
}


void
CalcLateTimes( pertADT pert )
{
	nodeT node;
	edgeT arista;
	digraphADT digrafo;
			
	digrafo = pert->digraph;
	UnmarkEdges( digrafo );			/*desmarco todas las aristas */
	
	SetBeginDiGraph( digrafo );
	node = GetNextNode( digrafo );	/*me situo en el primer nodo del digrafo */
	
	CalcLateRec( digrafo, node, arista );
}	

		
void
CalcMargins( pertADT pert )
{
	digraphADT digrafo;
	nodeT node;
	edgeT arista;
	
	digrafo = pert->digraph;
	UnmarkEdges( digrafo );
	
	SetBeginDiGraph( digrafo );
	node = GetNextNode( digrafo );
	
	CalcMarginsRec( digrafo, node, arista );
}

FILE * 
CreateDotFile(pertADT pert)
{
	
	FILE * gaux;
	infoNodoT * node, * naux;
	actividadT * eaux;

	if ( (gaux = fopen("graph.dot", "w+t")) == NULL)
		return NULL;
	
	fprintf(gaux, "digraph G {\n");
	fprintf(gaux, "center =  true;\n");
	fprintf(gaux, "rotate = 0;\n");
	fprintf(gaux, "nodesep = \"1.1 \";\n");
	fprintf(gaux, "rankdir = LR;\n");
	fprintf(gaux, "node [shape = Mrecord, style = rounded];\n");
	
	
	SetBeginDiGraph(pert -> digraph);
	while ( (node = GetNextNode(pert -> digraph)) != NULL )
	{
		fprintf(gaux, "nodo%d [ label = \"{ %d | {%d | %d}} \"];\n", node -> nombre, node -> nombre, node -> ci, node -> li);  
		SetIteratorEdge(pert -> digraph, node);
		while(GetNextEdge(pert -> digraph, node, (edgeT *)&eaux, (nodeT *)&naux))
			fprintf(gaux, "nodo%d -> nodo%d [label = %s, color = %s, style = %s, taillabel = %d, labeldistance = 3.5];\n", node -> nombre, naux -> nombre, eaux -> ID, ColorChooser(eaux -> margen), eaux -> duracion == 0 ? "dashed" : "bold", eaux -> duracion);		
	}
	
	fprintf(gaux,"}\n");
	fclose(gaux);
	return gaux;
}


int 
Calendar( pertADT pert, int frmLength, TimeUnit unit)
{
	FILE * calFile;
	char  * initDate, * start, * end;
	char * ficticia = "ficticia";
	infoNodoT * node, * naux;
	actividadT * eaux;
	char bkp[frmLength];
	
	if ( (calFile = fopen("calendar.txt", "w+t")) == NULL )
	{
		fprintf(stderr, "Calendar: No se pudo crear el calendario \n");
		return 0;
	}
	
	if ( (initDate = GetProyectStart(frmLength)) == NULL )
	{
		fprintf(stderr, "Calendar: Memoria insuficiente \n");
		fclose(calFile);
		return 0;
	}
	
	
	fprintf(calFile, "El proyecto comienza el dia %s\n", initDate);
	
	SetBeginDiGraph(pert -> digraph);
	
	while ( (node = GetNextNode(pert -> digraph)) != NULL )
	{
		SetIteratorEdge(pert -> digraph, (nodeT)node);
		
		while ( GetNextEdge(pert -> digraph, node, (edgeT *)&eaux, (nodeT *)&naux) )
		{
			if (strncmp(eaux -> ID, ficticia, 8) != 0)
			{
				if ( (start = GetActTime(initDate, unit, frmLength, node -> ci)) == NULL )
				{
					free(initDate);
					fclose(calFile);
					return 0;
				}
			
				if ( (end =  GetActTime(start, unit, frmLength, eaux -> duracion)) == NULL )
				{
					free(start);
					free(initDate);
					fclose(calFile);
					return 0; 
				}
				strcpy(bkp, end);
				fprintf(calFile, "La actividad %s: %s, empieza el %s y termina el %s \n", eaux -> ID, eaux -> descripcion, start, end);
				free(start);
				free(end);
			}
		}
	}
	
	fprintf(calFile, "El proyecto finaliza el dia %s\n", bkp);
	
	free(initDate);
	fclose(calFile);
	return 1;	
}


void
FreePert( pertADT pert )
{
	free( pert->vecActivities );
	free( pert->vecNodes );
	FreeQueue( pert->cola );
	FreeDiGraph( pert->digraph );
	free( pert );
}

	
int 
InsertTask( pertADT pert, char** campos )
{
	actividadT* NewAct;
	NewAct = malloc( sizeof( actividadT ));
	int pos;
		
	if( (pos = BuscarActividad( pert, campos[0])) >= 0 )
	{
		fprintf( stderr, "La actividad de ID %s ya existe en la red\n", campos[0]);
		return 0;
	}
	
	strcpy( NewAct->ID, campos[0] );
	strcpy( NewAct->descripcion, campos[1] );
	NewAct->duracion = atoi( campos[2] );
	NewAct->margen = -1;
	/*campos 3 tiene la actividad predecesora o '-'
	campos 4 tiene la actividad sucesora o '-' */
	
	if( ! VerifyInsertion( pert, NewAct, campos[3], campos[ 4 ] ) )
	{
		fprintf( stderr, "No es valida la insercion de la actividad\n");
		return 0;
	}
	
	UnmarkTimes(pert -> digraph);
	GetCPM(pert);
	
	return 1;
}

int 
ModifyTask(pertADT pert, int modchoice, char ** campos)
{
	infoNodoT nodosrc, nodotgt, nodoaux;
	nodesActivity* noditos;
	actividadT auxAct;
	edgeT arista;
	actividadT *act;
	int pos, posPrec, *vecSum;
	char *nombreAct = campos[0]; /* nombre de la actividad a modificar */
	char *choice = campos[modchoice];
	int prec = 1, num;
	
	noditos = pert->vecNodes;
	
	nodosrc.ci = nodosrc.li = nodotgt.ci = nodotgt.li = -1;
	nodoaux.ci = nodoaux.li = -1;
	
	/* busco actividad a modificar */
	if ( (pos = BuscarActividad(pert, nombreAct)) == -1 )
	{
		fprintf(stderr,"Error no se puede modificar la tarea, pues es inexistente\n");
		return 0;
	}
	
	/* nodos de la tarea a modificar */
	nodoaux.nombre = nodosrc.nombre = noditos[pos].nodeInicio;
	nodotgt.nombre = noditos[pos].nodeFin;
	
	GetEdge(pert->digraph, &nodosrc, &nodotgt, &arista);

	act = (actividadT*) arista;
	if( act->margen == 0 )
	{
		fprintf(stderr, "No se pueden modificar precedencias de actividades del camino critico\n");
		return 0;
	}

	memcpy(&auxAct, act, sizeof(actividadT));
	
	switch(modchoice)
	{
		case 1: /* modificar la duracion */
				if ( (num = GetInt(choice)) == -1)
					return 0;
					
				act -> duracion = atoi(choice);
				auxAct.duracion = act -> duracion; /* lo que cambia en la original, cambia en la copia */
				break;
		
		case 2:	/* modificar la descripcion */
				strcpy(act -> descripcion, choice);
				strcpy(auxAct.descripcion, choice);
				break;
		
		case 3: /* modificar las prcedencias */
				if (strcmp(choice,"-") == 0)
				{	
					nodosrc.nombre = 0;
					prec = 0;
				}
			
				else 
				{
					if ( (posPrec = BuscarActividad(pert, choice)) == -1 )
					{
						fprintf(stderr,"Error no se puede modificar la tarea, pues no existe la predecesora\n");
						return 0;
					}
				
				
					if (noditos[posPrec].nodeFin == nodotgt.nombre)
					{
						fprintf(stderr, "La tarea ya tiene esa precedencia\n");
						return 0;
					}
				}
				
				auxAct.ct = auxAct.lt = -1;
				
				if (nodosrc.nombre != 0 || prec)
				{
					nodoaux.nombre = noditos[posPrec].nodeFin;
					DeleteEdge(pert->digraph, &nodosrc, &nodotgt);
				}
				else
					DeleteEdge(pert->digraph, &nodoaux, &nodotgt);

				if (IsConnected(pert->digraph, &nodosrc, &nodotgt))
				{
					GetEdge(pert->digraph, &nodosrc, &nodotgt, &arista);
					if ( ((actividadT *)arista)->duracion != 0 )
					{
						fprintf(stderr, "Imposible modificar la actividad\n");
						return 0;
					}
				}
				
				if (prec == 0)
					CreateEdge(pert->digraph, &nodosrc, &nodotgt, &auxAct);
				else
					CreateEdge(pert->digraph, &nodoaux, &nodotgt, &auxAct);
				
				noditos[pos].nodeInicio = nodoaux.nombre;
				
				/*SendToSumider(digrafo, contadornodos );*/
				vecSum = malloc(sizeof(int) * (pert->cant));
				
				/* Creo un solo sumidero */
				GetVecSum(pert->digraph, &vecSum);
				
				auxAct.vecPredec[0] = 1;
				auxAct.vecPredec[1] = posPrec + 1;
				
				/* Si retorna 1, hay que sobreescribir la arista ficticia */
				
				if (CrearSumidero(pert, vecSum))
				{
					if (prec == 0)
						CreateEdge(pert -> digraph, &nodosrc, &nodotgt, &auxAct);
					else
						CreateEdge(pert -> digraph, &nodoaux, &nodotgt, &auxAct);
				}
				
				GetVecSum(pert->digraph, &vecSum);
				CrearSumidero(pert, vecSum);
				
				free( vecSum );
				
				break;
				
		default: return 0;
	}
	
	(pert->vecActivities)[pos] = auxAct;
	UnmarkTimes(pert -> digraph);
	GetCPM(pert);
	
	return 1;
}


int 
DeleteTask( pertADT pert, char* nombreAct )
{
	infoNodoT nodosrc, nodotgt;
	nodeT nodoaux;
	nodesActivity* noditos, *ficticias;
	edgeT arista, arista2;
	actividadT *act;
	int pos;
	
	noditos = pert->vecNodes;
	ficticias = pert->vecFic;

	/* busco actividad a eliminar */
	if ( (pos = BuscarActividad(pert, nombreAct)) == -1 )
	{
		fprintf(stderr,"Error no se puede eliminar la tarea, pues es inexistente\n");
		return 0;
	}
	
	nodosrc.nombre = noditos[pos].nodeInicio;
	nodotgt.nombre = noditos[pos].nodeFin;
	
	GetEdge(pert->digraph, &nodosrc, &nodotgt, &arista);
	 
	act = (actividadT*) arista;
	
	if ( act->margen == 0 )
	{
		fprintf(stderr,"Error no se puede eliminar la tarea, pues es una tarea critica\n");
		return 0;
	}	
	
	/* porq pregunta x esta condicion aca!? ver prueba1, borrar A y dps D... falla porq no pasa
	 * esta condicion y se deberia poder borrar, chequear para que casos se necesitaba esta condicion
	 * y ver como re adaptarla
	 */
	
	else if (OutputEdges(pert->digraph, &nodosrc) == 1)
	{
		fprintf(stderr,"Error no se puede eliminar la tarea, pues quedarian 2 sumideros.\n");
		return 0;
	}
		
	else if( InputEdges(pert->digraph, &nodotgt) == 1 )
	{
		if( ! OutputEdges( pert->digraph, &nodotgt ))
		{
			fprintf(stderr,"Error no se puede eliminar la tarea pues quedaria desconexo el grafo.\n");
			return 0;
		}
		else 
		{
			SetIteratorEdge( pert->digraph, &nodotgt );
			while( GetNextEdge(pert->digraph, &nodotgt, &arista2, &nodoaux ) )
			{
				if( ((actividadT*)arista2)->duracion != 0 )
				{
					fprintf(stderr,"No se debe eliminar dicha actividad\n");
					return 0;
				}

				if( InputEdges(pert->digraph, nodoaux) == 1 )
				{
					fprintf(stderr,"No se debe eliminar dicha actividad, quedarian varios sumideros\n");
					return 0;
				}	

			}
			SetIteratorEdge( pert->digraph, &nodotgt );
			while( GetNextEdge(pert->digraph, &nodotgt, &arista2, &nodoaux ) )
					DeleteEdge(pert->digraph, &nodotgt, nodoaux);
			
			DeleteNode( pert->digraph, &nodotgt );
		}
			
	}
	
	/* eliminio la arista */
	noditos[pos].logicErase = 1;
/*	pert->cant--; */
	
	DeleteEdge(pert->digraph, &nodosrc, &nodotgt);

	fprintf(stderr,"Actividad %s borrada...\n\n", nombreAct );
	UnmarkTimes(pert -> digraph);
	GetCPM(pert);

	return 1;
}


int
BuscarFicticia( nodesActivity* ficticias, int nodosrc, int nodotgt )
{
	int i = 0;
	while( ficticias[ i ].nodeFin != 0 )
	{
		if( ficticias[ i ].nodeInicio == nodosrc && ficticias [ i ].nodeFin == nodotgt )
			return i;
		i++;
	}
	return -1;
}


/* ---------------------------------------------------------------------------- */
/* Funciones estaticas de ModifyTask */ 
 
static int
GetInt( char *s )
{
	int num = -1;

	if( s==NULL )
		return num;

	num = 0;
	while( *s != '\0' )
	{
		if( !isdigit(*s) )
			return -1;
		num += Power(strlen(s)) * TONUMBER(*s);
		s++;
	}
	return num;
}

 
 
static int
Power(int pow)
{
	int num;
	int i;

	num=1;
	for( i = 1; i < pow; i++ )
		num *= 10;
		return num;
}


/* ---------------------------------------------------------------------------- */
/* Funciones estaticas de CalcEarlyTimes */

static void
CalcEarlyRec( digraphADT digrafo, nodeT node, edgeT arista )
{
	actividadT* edge;
	nodeT next;
	SetIteratorBFS( digrafo, node );
	node = GetNextNodeBFS( digrafo );
	
	
	while( (next = GetNextNodeBFS( digrafo )) != NULL  && IsConnected( digrafo, node, next) )
	{
		GetEdge( digrafo, node, next, &arista );
		edge = (actividadT*)arista;
		
		if( edge->tag == 0)
		{
			edge->tag = 1;
			if( ((infoNodoT*)next)->ci < (((infoNodoT*)node)->ci + edge->duracion) )
				((infoNodoT*)next)->ci = (((infoNodoT*)node)->ci + edge->duracion);
			edge->ct = ((infoNodoT*)node)->ci + edge->duracion;	
		}	
	}
	
	if( (node = GetNextNode( digrafo )) != NULL)
		CalcEarlyRec( digrafo, node, arista);
}

/* Funciones estaticas de InsertTask */

static int
BuscarActividad( pertADT pert, char* Actname )
{
	int i;
	nodesActivity* noditos;
	actividadT* actividades;
	
	noditos = pert->vecNodes;
	actividades = pert->vecActivities;
	for( i = 0; i < pert->cant; i++ )
	{
		if( noditos[ i ].logicErase == 0 )
			if( !strcmp( actividades[i].ID, Actname ) )
				return i;
	}
	return -1;
}	
	
static int
VerifyInsertion( pertADT pert, actividadT* NewAct,char* predecesoras, char* sucesoras )
{
	edgeT arista;
	actividadT* actividades;
	infoNodoT nodosrc, nodotgt;
	nodesActivity* noditos;
	char *aristaPrec = NULL, *aristaSuc = NULL;
	int cantprec = 0, cantsuc = 0;
	int ** vecSum, posicion;
	char* delims = ",";
	
	
	vecSum = malloc(2 * sizeof(int *));
	vecSum[0] = malloc(sizeof(int));
	vecSum[1] = malloc(sizeof(int));
	actividades = pert->vecActivities;
	noditos = pert->vecNodes;
	
	nodosrc.li = nodosrc.ci = nodotgt.ci = nodotgt.li = -1;
	
	if( strcmp( predecesoras, "-") == 0 )
		nodosrc.nombre = 0;
	
	else
	{
		aristaPrec = strtok( predecesoras, delims);
		if( (nodosrc.nombre = noditos[ BuscarActividad( pert, aristaPrec ) ].nodeFin )== -1 )
		{
			fprintf(stderr, "No existe dicha actividad predecesora...Insercion fallida \n");
			return 0;	
		}
		cantprec = 1;
	}
	
	if( strcmp( sucesoras, "-") == 0 )
	{
		GetVecSum(pert->digraph, vecSum);
		nodotgt.nombre = (*vecSum)[1];
	}
	
	else
	{
		aristaSuc = strtok(sucesoras, delims);
		
		if( (nodotgt.nombre = noditos[ BuscarActividad( pert, aristaSuc ) ].nodeInicio ) == -1 )
		{
			fprintf(stderr, "No existe dicha actividad sucesora...Insercion fallida \n");
			return 0;	
		}
		cantsuc = 1;
	}
	
	/* no permite insertar entre nodos de ID mayor a menor (esto provocaria un fallo en el CPM 
	 * pues el recorrido es al estilo BFS y no repite caminos (y por lo tanto no actualizaria
	 * bien los tiempos CI de los nodos si se permitiera este tipo de insercion
	 */
	
	if (nodotgt.nombre < nodosrc.nombre)
	{
		free(vecSum[0]);
		free(vecSum[1]);
		free(vecSum);
		printf("el nodo tgt es menor que el nodo src \n");
		return 0;
	}
	
	if( IsConnected( pert->digraph, &nodosrc, &nodotgt ) )
	{
		GetEdge( pert->digraph, &nodosrc, &nodotgt, &arista );
		if( ((actividadT*) arista )->duracion != 0 )
		{
			fprintf(stderr, "ya existe una actividad en ese lugar...Insercion fallida \n");
			return 0;
		}
	}
		
	if( pert->cant == pert->bloque )
	{
		if( (actividades = realloc( actividades, pert->bloque * 2 * sizeof(actividadT))) == NULL)
		{
			fprintf(stderr, "Insuficiente memoria...Insercion fallida \n");
			return 0;
		}
		if( (noditos = realloc( noditos, pert->bloque * 2 * sizeof(nodesActivity))) == NULL)
		{
			fprintf(stderr, "Insuficiente memoria...Insercion fallida \n");
			return 0;
		}
		pert->bloque *= 2;
	}
	
	CreateEdge( pert->digraph, &nodosrc, &nodotgt, NewAct );
	posicion = FindPosition( pert );
	
	(pert->vecNodes)[ posicion  ].nodeInicio = nodosrc.nombre;
	(pert->vecNodes)[ posicion  ].nodeFin = nodotgt.nombre;
	(pert->vecActivities)[ posicion ] = *NewAct;
	(pert->vecNodes)[ posicion  ].logicErase = 0;
	
	if( posicion > ( pert->cant - 1 ))
		pert->cant++;
	fprintf(stderr,"Actividad insertada...\n\n");
	return 1;
}
	
	
	
static int
FindPosition(pertADT pert)	
{
	int i;
	nodesActivity* nodos;
	
	nodos = pert->vecNodes;
	
	for(i = 0; i < pert->cant; i++)
	{
		if( nodos[i].logicErase == 1 )
			return i;
	}
	return pert->cant;
}

/*---------------------------------------------*/

/* Funciones estaticas de LoadPert */

static pertADT
NewPert( void )
{
	pertADT pert;

	if( (pert = malloc( sizeof( struct pertCDT ))) == NULL)
	{
		fprintf(stderr, "No se pudo alocar espacio para la estructura \n");
		return NULL;
	}
	pert->digraph = NULL;
	pert->cola = NULL;
	pert->vecActivities = NULL;
	pert->vecNodes = NULL;
	pert->vecFic = NULL;
	pert->cant = 0;
	pert->bloque = 0;
	return pert;
}

static int
LoadActivities( FILE* archivo, actividadT** vecActividades, int* pertblock )	/* este main haria de GetLoades, recordar esto para hacer los malloc de los arreglos */
{
	char *buffer, *salida, *auxbuffer;
	int indiceActividad=0, numTarea=0, bloque = BLOQUE_ACT;
	actividadT actividad, *vecActAux;
			
	/* buffer para parsear */
	if ( (buffer = malloc(sizeof(char) * MAXBUFFER)) == NULL )
	{
		fprintf(stderr,"No hay memoria disponible para crear el buffer\n");
		return -1;
	}
	
	auxbuffer = buffer;

	/* arreglo de actividadT */
	if ( (*vecActividades = malloc(sizeof(actividadT) * bloque)) == NULL )
	{
		fprintf(stderr,"No hay memoria disponible para almacenar las actividades\n");
		return -1;	
	}

	/* comienza llenado de arreglo actividadT */
	while ( (salida = fgets(buffer, MAXBUFFER, archivo)) != NULL && salida[0] != '\n' )	/* levanto linea a parsear del archivo */
	{
		if ( (getID(&buffer, MAXBUFFER, &actividad)) == 0 )
		{
			fprintf(stderr,"\nDato incorrecto al levantar nombre de actividad\n");
			return -1;
		}
				
		getDetalle(&buffer, &actividad, MAXDETALLE);
				
		actividad.duracion = getNum(&buffer, MAXBUFFER);
		actividad.tag = 0;
		actividad.ct = actividad.lt = actividad.margen = -1;
				
		if ( getPredec(&buffer, *vecActividades, &actividad, numTarea) == -1)
		{	
			fprintf(stderr, "Dato incorrecto al levantar actividad predecesora\n");
			return -1;	
		}
	
		/* cargo la actividad al arreglo de actividades */
		if ( indiceActividad == bloque )
		{
			bloque += BLOQUE_ACT; 

			if ( (vecActAux = realloc(*vecActividades,bloque * sizeof(actividadT))) == NULL )
			{
				free(*vecActividades);
				fprintf(stderr,"No hay memoria para guardar las actividades\n");
				return -1;
			}
			(*vecActividades) = vecActAux;	
		}
		
		(*vecActividades)[indiceActividad++] = actividad;
		
		numTarea++;
		buffer = auxbuffer;
	}
	*pertblock = bloque;
	return numTarea;
}


static digraphADT
ArmaDigrafo( pertADT pert, int cantActividades )
{
	digraphADT digrafo;
	int contadornodos = 1, i, cantprecedencias, backCantAct, indice_actividad = 0, indice_ficticias = 0;
	actividadT infoArista;
	int actpredec[ cantActividades ]; /* actividades predecesoras que devuelve las precedencias de una actividad */
	infoNodoT fuente, nodosrc, nodotgt, auxNodo;
	fuente.nombre = 0;
	nodosrc.ci = nodosrc.li = nodotgt.li = nodotgt.ci = -1;
	nodesActivity* vecNodos, *vecFicticias;
	actividadT* arreglo_actividades;
	
	arreglo_actividades = pert->vecActivities;
		
	digrafo = NewDiGraph( CmpNodes, sizeof( infoNodoT ), sizeof( actividadT ) );
		
	if( (pert->vecNodes = malloc( sizeof( nodesActivity ) * pert->bloque)) == NULL )
		return NULL;
	vecNodos = pert->vecNodes;
	
	if( (pert->vecFic = calloc(pert->bloque,  sizeof( nodesActivity ) )) == NULL )
		return NULL;
	vecFicticias = pert->vecFic;
	
	backCantAct = cantActividades;	
		
	while( cantActividades-- )
	{
		cantprecedencias = Getprec( arreglo_actividades, actpredec, indice_actividad );
		
		if( cantprecedencias == 0 )
		{
			nodotgt.nombre = contadornodos;	
			CreateEdge( digrafo, &fuente, &nodotgt, &arreglo_actividades[ indice_actividad ]);
			
			vecNodos[ indice_actividad ].nodeInicio = 0;
			vecNodos[ indice_actividad ].nodeFin = contadornodos;
			vecNodos[ indice_actividad ].logicErase = 0;
		}
		
		else if( cantprecedencias == 1 )
		{
			nodosrc.nombre = vecNodos[ actpredec[ 0 ] - 1 ].nodeFin;
			nodotgt.nombre = contadornodos;
			
			CreateEdge( digrafo, &nodosrc, &nodotgt, &arreglo_actividades[ indice_actividad ] );
			
			vecNodos[ indice_actividad ].nodeInicio = nodosrc.nombre;
			vecNodos[ indice_actividad ].nodeFin = contadornodos;	
			vecNodos[ indice_actividad ].logicErase = 0;
		}
		
		else if( cantprecedencias >= 2)
		{
			auxNodo.nombre = vecNodos[ actpredec[ 0 ]- 1 ].nodeFin;
					
			infoArista.duracion = 0;
			strcpy( infoArista.ID, "ficticia");
			nodotgt.nombre = contadornodos;
			
			for( i = 0; i < cantprecedencias; i++)
			{
				nodosrc.nombre = vecNodos[ actpredec[ i ]- 1 ].nodeFin;
				/* creacion arista ficticia */
				CreateEdge( digrafo, &nodosrc, &nodotgt, &infoArista );
				
				vecFicticias[ indice_ficticias ].nodeInicio = nodosrc.nombre;
				vecFicticias[ indice_ficticias ].nodeFin = nodotgt.nombre;
				vecFicticias[ indice_ficticias ].logicErase = 0;
				indice_ficticias++;
			}
			
			nodosrc.nombre =  contadornodos++;
			nodotgt.nombre = contadornodos;
			
			CreateEdge( digrafo, &nodosrc, &nodotgt, &arreglo_actividades[ indice_actividad ] );
				
			vecNodos[ indice_actividad ].nodeInicio = nodosrc.nombre;
			vecNodos[ indice_actividad ].nodeFin = nodotgt.nombre;
			vecNodos[ indice_actividad ].logicErase = 0;	
		}
		contadornodos++;
		indice_actividad++;
	}
	
	return digrafo;
}

static int
getID(char **buffer, int dimBuffer, actividadT *actividad)
{
	char vecAux[MAX_ID+1];
	int c, i=0;
	
	while ( (c = (*buffer)[0]) != ';' && i < MAX_ID )
	{
		if (!isalnum(c))
			return 0;
			
		vecAux[i++] = c;
		(*buffer)++;	
	}
	
	vecAux[i] = 0;
	strcpy( actividad->ID, vecAux );
	
	return 1;
}

static int 
getDetalle(char **buffer, actividadT *actividad, int dimDetalle)
{
	int c, flagOK=0, i=0;
	
	(*buffer)++; /* para saltear el separador ';' del campo anterior */
	
	while ( (c = (*buffer)[0]) != ';' )
	{
		if (dimDetalle <= 0)
			return 0;
				
		(actividad->descripcion)[i++] = c;
		(*buffer)++;
		flagOK++;
		dimDetalle--;
	}
	(actividad->descripcion)[i] = '\0';	/* marca de fin del string */
	
	if(flagOK)
		return 1;
	
	return 0; /* caso de error */	
}

static int
getNum(char **buffer, int dimBuffer)
{
	char number[4];
	int c, i=0, flagOK=0;
	
	c = (*buffer)[0];

	if (dimBuffer <= 0)
		return -1;
	
	if ( !isdigit(c) && c != ';' )
		return -1;	/* error - no es un digito */
	
	if (c == ';')
		(*buffer)++;	
		
	while ( (c = (*buffer)[0]) != '\n' && isdigit(c) && dimBuffer != 0 )
	{
		number[i++] = c;
		(*buffer)++;
		flagOK++;
		dimBuffer--;
	}
	
	if (flagOK)
		return atoi(number);
	
	return -1;
}

static int 
getPredec(char **buffer, actividadT *vecActividades, actividadT *actividad, int numTarea)
{
	char actPre[MAX_ID];
	int c, j=0, pos=1;
	estadoT estado;
		
	estado = INICIAL;
	
	(*buffer)++; /* salteo el ';' del campo anterior */
	
	while ( estado != FIN )
	{
		c = (*buffer)[0]; /* leo caracter */
		
		switch(estado)
		{
			case INICIAL:
				if ( c == '{' )
				{
					estado = POS_PRIMERO;
					(*buffer)++;
				}
				else
					estado = ERROR;
				break;
			
			case POS_PRIMERO:
				if ( c == '-' )
				{
					estado = POS_VACIO;
					(*buffer)++;
				}
				else if (isalnum(c))
				{
					actPre[j++] = c;	/* guardo el digito */
					estado = POS_DIG;
					(*buffer)++;
				}
				else
					estado = ERROR;
				break;
			
			case POS_VACIO:
				if ( c == '}' )
				{	
					(actividad->vecPredec)[1] = 0;
					estado = FIN;
				}
				else
					estado = ERROR;
				break;									
		
			case POS_DIG:
				if (isalnum(c))
				{
					actPre[j++] = c;
					estado = POS_DIG;
					(*buffer)++;
				}
				else if ( c == ',' )
				{
					actPre[j] = '\0';	/* marca de fin para el atoi y que no muestre basura */
					if ( ((actividad->vecPredec)[pos++] = validatePredec(actPre, vecActividades, numTarea)) == -1)
					{
						estado = ERROR;
						break;
					}
					j=0;
					estado = POS_MASDIG;
					(*buffer)++;	
				}
				else if ( c == '}' )
				{
					actPre[j] = '\0';	/* marca de fin para el atoi y que no muestre basura */
					if ( ((actividad->vecPredec)[pos++] = validatePredec(actPre, vecActividades, numTarea)) == -1)
					{	
						estado = ERROR;
						break;
					}
					else
					{
						estado = FIN;
						break;
					}
				}
				else
					estado = ERROR;
				break;
				
			case POS_MASDIG:
				if (isalnum(c))
				{
					actPre[j++] = c;
					estado = POS_DIG;
					(*buffer)++;
				}
				else
					estado = ERROR;
				break;
			
			case ERROR:
				return -1;
				break;
			
			case FIN:
				break;
		}
	}							
				
	(actividad->vecPredec)[0] = pos-1; /* cantidad de actividades precedentes de la actividad */
	
	return 1;
}

static int
Getprec( actividadT* vec_act, int* actpredec, int indice )
{
	int i;
	int cant = (vec_act[ indice ]).vecPredec[0];
	for(i = 1; i <=  cant; i++ )
		actpredec[ i-1 ] = (vec_act[ indice ]).vecPredec[ i ];
		
	return cant;
}
	
static void
GetVecSum(digraphADT digrafo, int **vecSum)
{
	int i=1;
	nodeT nodo;
	
	/* busco todos los nodos que son sumideros */
	SetBeginDiGraph(digrafo);
	while ( (nodo = GetNextNode(digrafo)) != NULL )
		if (OutputEdges(digrafo, nodo) == 0)
			(*vecSum)[i++] = ((infoNodoT*)nodo)->nombre;
		
	(*vecSum)[0] = i - 1; /* cantidad de nodos sumideros */
}

static int 
CrearSumidero(pertADT pert, int *vecSum)
{
	int sumidero, i, cantSum;
	infoNodoT nodosrc, nodotgt, nodo_a_borrar;
	actividadT *edge;
	int posAct;
	int esFic = 0;
	
	cantSum = vecSum[0];
	sumidero = vecSum[cantSum];
	nodotgt.nombre = sumidero;
	nodotgt.ci = nodotgt.li = nodosrc.ci = nodosrc.li = -1;
	
	for (i=1; i<cantSum; i++)
	{
		nodo_a_borrar.nombre = vecSum[i];
		nodosrc.nombre = FindNodeSrc(pert -> vecActivities, pert -> vecNodes, vecSum[i], pert -> cant);		
		
		if (nodosrc.nombre == -1)
			nodosrc.nombre = FindNodeSrc(pert -> vecActivities, pert -> vecFic, vecSum[i], pert -> cant);		
		
		if (nodosrc.nombre != -1)
			GetEdge(pert -> digraph, &nodosrc, &nodo_a_borrar, (edgeT *)&edge);
		
		/* lo que esta comentado adentro del if fue el cambio q hice... */
		/* si del prueba3, borro D y dps quiero modificar la precedencia de G q sea C...
		 * al borrar D, el nodo de ID 4 MURIO y no se xk.. el nombre de nodosrc es 4
		 * CHEQUEAR!
		 */ 
		
		if (/*edge != NULL &&*/ strcmp(edge -> ID, "ficticia") != 0)
		{	
			CreateEdge(pert -> digraph, &nodosrc, &nodotgt, edge);
			posAct = BuscarActividad(pert, edge -> ID);
			(pert -> vecNodes)[posAct].nodeFin = nodotgt.nombre;
		}
		else
			esFic = 1;
		
		DeleteNode(pert -> digraph, (nodeT) &nodo_a_borrar); 
	}
	
	return esFic;
}	

static int 
FindNodeSrc(actividadT *vecActividad, nodesActivity *vecNodos, int nodoFin, int cantActividades)
{
	int i;
	
	for (i=0; i<cantActividades; i++)
		if ( vecNodos[i].nodeFin == nodoFin)
			return vecNodos[i].nodeInicio;
			
	return -1;
}

static int
CmpNodes( nodeT nodo1, nodeT nodo2)
{
	int N1 = ((infoNodoT*)nodo1)->nombre;
	int N2 = ((infoNodoT*)nodo2)->nombre;
	
	if(N1 > N2 )
		return 1;
	else if( N1 < N2 )
		return -1;
	
	return 0;
}

static int
validatePredec(char *actPre, actividadT *vecActividad, int numTarea)
{
	int i;
	
	for (i=0; i<numTarea; i++)
		if ( !strcmp(actPre, vecActividad[i].ID) )
			return i+1;
	
	return -1;
}

/* Funciones estaticas de GetCPM */

static void
UnmarkEdges(digraphADT digrafo )
{
	edgeT arista;
	nodeT node;
	arista = malloc( sizeof(actividadT));
	SetBeginDiGraph( digrafo );
	node = GetNextNode( digrafo );	
	
	UnmarkRec( digrafo, node, arista );
}

static void
UnmarkRec( digraphADT digrafo, nodeT node, edgeT arista )
{
	nodeT next;
	
	SetIteratorBFS( digrafo, node );
	node = GetNextNodeBFS( digrafo );
	
	while( (next = GetNextNodeBFS( digrafo )) != NULL  && IsConnected( digrafo, node, next) )
	{
		GetEdge( digrafo, node, next, &arista );
		((actividadT*)arista)->tag = 0;
	}
	
	if( (node = GetNextNode( digrafo )) != NULL)
		UnmarkRec( digrafo, node, arista );
}

static void
CPMRec( digraphADT digrafo, nodeT node, queueADT cola, edgeT arista, int* fin )
{
	nodeT next;
	actividadT* edge;
	SetIteratorBFS( digrafo, node );
	node = GetNextNodeBFS( digrafo ); /* node tiene el primer nodo del digrafo */
	
	/* voy iterando sobre los nodos adyacentes a node */	
	while ( (next = GetNextNodeBFS( digrafo )) != NULL && IsConnected( digrafo, node, next ) && *fin == 0 )
	{
		GetEdge( digrafo, node, next, &arista ); /*traigo la arista que los conecta  */
		edge = (actividadT*)arista;
		
		if( edge->tag == 0 ) /* si ya la recorri no entro */
		{
			edge->tag = 1;
			if( edge->margen == 0 )  /*  pregunto el margen y si es 0 la apilo */
			{
				Enqueue( cola, &(edge->ID) );  /*guardo el ID de la tarea critica */
				if( IsLastNode( digrafo, next ))
					*fin = 1;
				else
					CPMRec( digrafo, next, cola, arista, fin );
				if(*fin == 0)			/* si sali de las recursivas y no llegue al final, desencolo */
				{
				/*	if( !QueueIsEmpty( cola ) );
						Dequeue( cola, &arista); */
				}
			}
		}	
	}
}

	
static void
UnmarkTimes (digraphADT digrafo )
{
	nodeT node;
	SetBeginDiGraph( digrafo );
	node = GetNextNode( digrafo );	
	
	UnmarkTimesRec( digrafo, node );
}
	
static void
UnmarkTimesRec( digraphADT digrafo, nodeT node )
{
	nodeT next;
	
	SetIteratorBFS( digrafo, node );
	node = GetNextNodeBFS( digrafo );
	((infoNodoT*)node)->li = -1;
	while( (next = GetNextNodeBFS( digrafo )) != NULL  && IsConnected( digrafo, node, next) )
		((infoNodoT*)next)->li = -1;
		
	if( (node = GetNextNode( digrafo )) != NULL)
		UnmarkTimesRec( digrafo, node );
}		

/* Funciones estaticas de CalcLateTimes */

static void
CalcLateRec( digraphADT digrafo, nodeT node, edgeT arista )
{
	nodeT next;
	
	SetIteratorBFS( digrafo, node );	
	node = GetNextNodeBFS( digrafo );   /* hago bfs a partir de este nodo */
	
	if( !IsLastNode( digrafo, node ) )    /* mientras no sea el ultimo  y este conectado con next */
	{
		while( (next = GetNextNodeBFS( digrafo )) != NULL  && IsConnected( digrafo, node, next) )
		{
			GetEdge( digrafo, node, next, &arista );
			if( ((actividadT*)arista)->tag == 0 )
			{
				CalcLateRec( digrafo, next, arista );
				
				((actividadT*)arista)->tag = 1;   /* cuando salgo de la recursiva, tageo la arista y seteo los tiempos */
				
				if( ((infoNodoT*)node)->li == -1 ||  ((infoNodoT*)node)->li > ((infoNodoT*)next)->li - ((actividadT*)arista)->duracion )
					((infoNodoT*)node)->li = ((infoNodoT*)next)->li - ((actividadT*)arista)->duracion;
				((actividadT*)arista)->lt = ((infoNodoT*)node)->li + ((actividadT*)arista)->duracion;	
			
				SetIteratorBFS( digrafo, node );	/* y vuelvo a iterar desde ese nodo */
				node = GetNextNodeBFS( digrafo );
			}
		}		
	}	
	else
		((infoNodoT*)node)->li = ((infoNodoT*)node)->ci;	
}

/* Funciones estaticas de CalcMargins */

static void
CalcMarginsRec( digraphADT digrafo, nodeT node, edgeT arista )
{
	actividadT* edge;
	nodeT next;
	SetIteratorBFS( digrafo, node );
	node = GetNextNodeBFS( digrafo );
	
	while( (next = GetNextNodeBFS( digrafo )) != NULL  && IsConnected( digrafo, node, next) )
	{
		GetEdge( digrafo, node, next, &arista );
		edge = (actividadT*)arista;
		
		if( edge->tag == 0)
		{
			edge->tag = 1;
			edge->margen = ( ((infoNodoT*)next)->li - edge->duracion - ((infoNodoT*)node)->ci );
		}	
	}
	
	if( (node = GetNextNode( digrafo )) != NULL)
		CalcMarginsRec( digrafo, node, arista);
}

/* Funciones estaticas de CreateDotFile */

static char *
ColorChooser(int margen)
{
	char * crit = "red";
	char * normal = "black";
	
	if (margen == 0)
		return crit;
	
	return normal;
}

/* Funciones estaticas de Calendar */

static char *
GetProyectStart(int frmlength)
{
	char * init;
	char * extFormat = "dd/mm/yyyy hh:mm";
	char * defFormat = "dd/mm/yyyy";
	char * day, * month, * year, * hour, * minute;
	int exit = 0;
	int days, months, years, hours ,minutes;
	int c;
	char letra;
	
	days = months = years = hours = minutes = 0;
	
	if ( (init = calloc(frmlength, sizeof(char))) == NULL )
			return NULL;
	
	printf("Ingrese la fecha de inicio del proyecto en formato %s \n", frmlength >= 12 ? extFormat : defFormat);
	
	while(!exit)
	{
		if (frmlength < 12)
			c = scanf("%d/%d/%d%c", &days, &months, &years, &letra);
		else
			c = scanf("%d/%d/%d %d:%d%c", &days, &months, &years, &hours, &minutes, &letra);
			
		if ( (frmlength < 12 && (c != 4 || letra != '\n')) || (frmlength >= 12 && (c != 6 || letra != '\n')) )
		{
			printf("error, el formato a ingresar debe ser %s \n", frmlength >= 12 ? extFormat : defFormat);
			while( (c = getchar() != '\n'));
		}
		
		else if (!checkStart(days, months, years, hours, minutes));
		
		else
			exit = 1;
	}
	
	if ( (day = transfToDate(days, 2)) == NULL)
		return NULL;
	if ( (month = transfToDate(months, 2)) == NULL)
		return NULL;
	if ( (year = transfToDate(years, 4)) == NULL)
		return NULL;
	
	if (hours != 0 || minutes != 0)
	{
		if ( (hour = transfToDate(hours, 2)) == NULL )
			return NULL;
		if ( (minute = transfToDate(minutes, 2)) == NULL )
			return NULL;
		strcat(init, day);
		strcat(init, "/");
		strcat(init, month);
		strcat(init, "/");
		strcat(init, year);
		strcat(init, " ");
		strcat(init, hour);
		strcat(init, ":");
		strcat(init, minute);
		free(hour);
		free(minute);
	}
	else
	{
		strcat(init, day);
		strcat(init, "/");
		strcat(init, month);
		strcat(init, "/");
		strcat(init, year);
	}
	
	free(day);
	free(month);
	free(year);
	return init;		
}

static int
checkStart(int days, int months, int years, int hours, int minutes)
{
	int ok = 1;
	
	if (days <= 0 || days > CalcDays(months, years))
	{
		ok = 0;
		fprintf(stderr, "El dia de inicio es invalido \n");
	}
	else if (months < 1 || months > 12)
	{
		ok = 0;
		fprintf(stderr, "El mes de inicio es invalido \n");
	}
		
	else if (years < 0 || years < 1000 || years > 9999)
	{
		ok = 0; /* no se va a tener en cuenta que el año pueda ser 10000!! */
		fprintf(stderr, "El año de inicio es invalido \n");
	}
	
	else if (hours != 0 || minutes != 0)
	{
		if (hours < 0 || hours > 23)
		{
			ok = 0;
			fprintf(stderr, "La hora de inicio es invalida \n");
		}
		else if (minutes < 0 || minutes > 59)
		{
			ok = 0;
			fprintf(stderr, "Los minutos elegidos para el inicio del proyecto no son correctos \n");
		}
	}
	
	return ok; 
}

static int
CalcDays(int months, int years)
{
	int totaldays;
	
	if (months > 1 && months < 8)
	{
		if (months != 2 && months % 2 == 0 )
			totaldays = 30;
		
		else if (months == 2 && years % 4 == 0)
			totaldays = 29;
		
		else if (months == 2)
			totaldays = 28;
		else
			totaldays = 31;
	}
	else
	{
		if (months % 2 == 0)
			totaldays = 31;
		else
			totaldays = 30;
	}
	
	return totaldays;
}

static char *
transfToDate(int num, int cantDigits)
{
	char * aux;
	
	if ( (aux = malloc((cantDigits + 1) * sizeof(char))) == NULL )
		return NULL;
		
	sprintf(aux, "%.2d", num);
	
	return aux; 
}

static char *
GetActTime(char * initDate, TimeUnit unit, int frmLength, int startTime)
{
	char * rta;
	char month[3] = {0};
	char year[5] = {0};
	int ok, i;
	
	if ( (rta = calloc(frmLength, sizeof(char))) == NULL)
		return NULL;
	
	strcpy(rta, initDate);
	
	switch(unit)
	{
		case MINUTO:
					ok = addUnits(startTime, &rta, 14, 60);
					break;
					
		case HORA:
					ok = addUnits(startTime, &rta, 11, 24);
					break;
					
		case DIA:
					strncpy(month, &(initDate[3]), 2);
					strncpy(year, &(initDate[6]), 4); 
					ok = addSpecial(startTime, &rta, month, year);
					break;
		case SEM:
					for ( i = 0 ; i < 7 ; i++)
					{
						strncpy(month, &(initDate[3]), 2);
						strncpy(year, &(initDate[6]), 4);
						ok = addSpecial(startTime, &rta, month, year);
						if (!ok)
							break;
					}
					break;
		case MES:
					ok = addUnits(startTime, &rta, 3, 12);
					break;
		case ANIO:
					ok = addUnits(startTime, &rta, 6, 0);
					break;
		default:
					fprintf(stderr, "Error en la unidad de tiempo \n");
					free(rta);
					return NULL;
	}
	
	if(!ok)
	{
		fprintf(stderr, "El calendario no soporta años mayores a 9999 \n");
		return NULL;
	}
		
	return rta;
}

static int
addUnits(int startTime, char ** newDate, int pos, int timeLimit)
{
	int newUnit;
	int oldUnit = 0;
	int totalUnit = 0;
	int i, j, k;
	char aux[3] = {0};
	char month[3] = {0};
	char year[5] = {0};
	
	if (timeLimit != 0)
		j = 1;
	else
		j = 3;
	
	/* transforma en int la unidad de tiempo que se actualizara  */
	
	for (i = 0, k = j ; i <= j ; i++, k--)	
		oldUnit += ((*newDate)[pos+i] - '0') * pow(10, k);
	
	/* calcula la nueva unidad a modificar */
	
	newUnit = oldUnit + startTime;
	
	if (timeLimit == 0 && newUnit > 9999)
		return 0;
	
	
	/* chequea si la suma de la vieja unidad de tiempo con startTime se excede de rango
	 * ejemplo: sumo 14 minutos a 15:59 -> 16:13
	 */
	
	while (newUnit - timeLimit > 0 && timeLimit != 0)
	{
		newUnit -= timeLimit;
		totalUnit++;
	}
	
	/* se transforma la nueva unidad a string */
	
	sprintf(aux, "%.2d", newUnit);
	
	/* y se la actualiza sobre el string original */
	
	if(timeLimit != 0)
		strncpy(&((*newDate)[pos]), aux, 2);
	else
		strncpy(&((*newDate)[pos]), aux, 4);
	
	/* se chequea si se excedio el rango y hay que modificar un nivel superior de unidad de tiempo */
	
	if (totalUnit > 0)
	{
		if (timeLimit == 60) /* si sumaron minutos que excedieron el rango, se sumaran horas */
		{
			addUnits(totalUnit, newDate, 10, 24);
		}
		
		else if (timeLimit == 24) /* idem pero con horas, dias */
		{
			strncpy(month, &((*newDate)[3]),2 );
			strncpy(year, &((*newDate)[6]), 4); /* paso a string el mes y año ya que definen el rango del dia */
			addSpecial(totalUnit, newDate, month, year );
		}
		
		else /* idem pero con mes año, el caso dia-mes se contempla en la funcion addSpecial */
			addUnits(totalUnit, newDate, 6, 0);
	}
			
	return 1;
}

static int
addSpecial(int startTime, char ** newDate, char * month, char * year)
{
	int months, years;
	int oldUnit, newUnit;
	int timeLimit, ok;
	int totalUnit = 0;
	char aux[3] = {0};
	
	months = atoi(month);
	years = atoi(year);
	
	timeLimit = CalcDays(months, years);
	
	oldUnit = ((*newDate)[0] - '0') * 10 + ((*newDate)[1] - '0');
	newUnit = oldUnit + startTime;
	
	
	while (newUnit - timeLimit > 0)
	{
		newUnit -= timeLimit;
		totalUnit++;
		months++;
		
		if (months == 13)
		{	
			months = 1;
			years++;
		}
		
		timeLimit = CalcDays(months, years);
	}
	
	/* se transforma la nueva unidad a string */
	
	sprintf(aux, "%.2d", newUnit);
	
	/* y se la actualiza sobre el string original */
	
	strncpy(&((*newDate)[0]), aux, 2);
	
	if (totalUnit > 0)
		ok = addUnits(totalUnit, newDate, 3, 12);
	
	if (!ok)
		return 0;
	return 1;
}
